/*+**************************************************************************/
/***                                                                      ***/
/***   This file is distributed under a BSD license.                      ***/
/***   See LICENSE.txt for details.                                       ***/
/***                                                                      ***/
/**************************************************************************+*/

asc
{
  cbuffer Wz4ShaderCamera : register(c0) : slot vs 0
  {
    row_major float4x4 MVP;         // model view projection matrix
    float3 LightPos;                // object space light source position
    float4 EyePos;                  // object space camera position. w is alpha-distance scale
    row_major float4x4 ShadowMatrix; 
    extern void Init(const sViewport *vp)
    {
      sMatrix34 mat;
      MVP = vp->ModelScreen;
      ShadowMatrix.Init();

      mat = vp->Model;
      mat.TransR();
      LightPos = vp->Camera.l * mat;
      EyePos = vp->Camera.l * mat;
      EyePos.w = 1;
    }
  };
  cbuffer Wz4ShaderUV : register(c12) : slot vs 1
  {
    float4 UV[6];                 // uv0.xy , uv1.xy matrix
    float4 pad[2];
    extern void Init()
    {
      UV[0].Init(1,0,0,0);
      UV[1].Init(0,1,0,0);
      UV[2].Init(1,0,0,0);
      UV[3].Init(0,1,0,0);
      UV[4].Init(1,0,0,0);
      UV[5].Init(0,1,0,0);
    }
  };
}

/****************************************************************************/

material Wz4XShader
{
  vs asc vs_3_0
  {
    permute Wz4ShaderVSPerm
    {
      DetailTex { DetailUV0,DetailUV1,DetailPos,DetailNorm,DetailRefl };
      SkinEnable;
      NeedTangent;
      Shadow { ShadowOff,ShadowReceive,ShadowReceivePS3 };
    };
    use Wz4ShaderVSPerm;
    use Wz4ShaderCamera;
    use Wz4ShaderUV;
    void main
    (
      in float4 in_pos : POSITION,
      in float3 in_norm : NORMAL,
      in float4 in_tang : TANGENT : pif(NeedTangent),
      in float4 in_uv : TEXCOORD0,
      in int4 in_index : BLENDINDICES : pif(SkinEnable),
      in float4 in_weight : BLENDWEIGHT : pif(SkinEnable),

      out float4 out_uv01 : TEXCOORD0,
      out float3 out_norm : TEXCOORD1,
      out float4 out_tang : TEXCOORD2 : pif(NeedTangent),
      out float3 out_eye : TEXCOORD3,
      out float2 out_uv23 : TEXCOORD4,
      out float4 out_shadow : TEXCOORD5 : pif(Shadow!=ShadowOff),
      out float4 out_pos : POSITION,

      uniform float4 Skinning[42] : register(c20) : pif(SkinEnable),      
    )
    {
      out_uv01.x = dot(float4(in_uv.x,in_uv.y,0,1),UV[0]);
      out_uv01.y = dot(float4(in_uv.x,in_uv.y,0,1),UV[1]);
      out_uv01.z = dot(float4(in_uv.x,in_uv.y,0,1),UV[2]);
      out_uv01.w = dot(float4(in_uv.x,in_uv.y,0,1),UV[3]);

      out_norm = normalize(in_norm);
      pif(NeedTangent)
      {
        out_tang.xyz = normalize(in_tang.xyz);
        out_tang.w = in_tang.w;        
      }

      out_eye = (in_pos.xyz-EyePos.xyz)*EyePos.w;

      pif(SkinEnable)
      {
        float4 sm0,sm1,sm2,n;
        
        sm0  = in_weight.x * Skinning[in_index.x+0];
        sm1  = in_weight.x * Skinning[in_index.x+1];
        sm2  = in_weight.x * Skinning[in_index.x+2];
        sm0 += in_weight.y * Skinning[in_index.y+0];
        sm1 += in_weight.y * Skinning[in_index.y+1];
        sm2 += in_weight.y * Skinning[in_index.y+2];
        sm0 += in_weight.z * Skinning[in_index.z+0];
        sm1 += in_weight.z * Skinning[in_index.z+1];
        sm2 += in_weight.z * Skinning[in_index.z+2];
        sm0 += in_weight.w * Skinning[in_index.w+0];
        sm1 += in_weight.w * Skinning[in_index.w+1];
        sm2 += in_weight.w * Skinning[in_index.w+2];
        
        n = float4(in_pos.xyz ,1);
        in_pos.x  = dot(n,sm0);
        in_pos.y  = dot(n,sm1);
        in_pos.z  = dot(n,sm2);
        n = float4(out_norm.xyz ,0);
        out_norm.x = dot(n,sm0);
        out_norm.y = dot(n,sm1);
        out_norm.z = dot(n,sm2);
        pif(NeedTangent)
        {
          n = float4(out_tang.xyz ,0);
          out_tang.x = dot(n,sm0);
          out_tang.y = dot(n,sm1);
          out_tang.z = dot(n,sm2);
        }
        
        out_pos = mul(in_pos,MVP);
      }
      pelse
      {
        out_pos = mul(in_pos,MVP);
      }

      float4 uv;
      pif(DetailTex==DetailUV0)  uv = float4(in_uv.xy,0,1);
      pif(DetailTex==DetailUV1)  uv = float4(in_uv.zw,0,1);
      pif(DetailTex==DetailPos)  uv = float4(in_pos.xyz,1);
      pif(DetailTex==DetailNorm) uv = float4(in_norm.xyz,1);
      pif(DetailTex==DetailRefl)
      {
        out_uv23.xy = normalize(reflect(out_eye,in_norm.xyz)).xy*0.5+0.5;
      }
      pelse
      {
        out_uv23.x = dot(uv,UV[4]);
        out_uv23.y = dot(uv,UV[5]);
      }

      pif(Shadow!=ShadowOff)
      {
        out_shadow = mul(in_pos,ShadowMatrix);
      }
    }
  }

  ps asc ps_3_0
  {
    permute Wz4ShaderPSPerm
    {
      TexBump;
      TexSpecularCube;
      TexDetail { TexDetailOff,TexDetailMul,TexDetailAdd,TexDetailBump,TexDetailSpecMul };
      TexDiffuseCube;
      Alpha { AlphaOne,AlphaDist,AlphaDiffuse };
//      TexEnvi;
      Shadow { ShadowOff,ShadowReceive,ShadowReceivePS3 };
      assert(TexDetail==TexDetailBump implies TexBump);
      assert(TexDetail==TexDetailSpecMul implies TexSpecularCube);
    };

    sampler2D s0 : register(s0);      // normal map
    sampler2D s1 : register(s1);      // diffuse map
    sampler2D s2 : register(s2);      // detail map
    samplerCUBE cubespec : register(s3);    // specular light
    samplerCUBE cubediff : register(s4);    // diffuse light
    sampler2D s5 : register(s5);      // envi map (actually useless)
    sampler2D s6 : register(s6);      // shadow map
    
    use Wz4ShaderPSPerm;

    void main
    (
      in float4 uv01 : TEXCOORD0,
      in float3 norm : TEXCOORD1,
      in float4 tangs : TEXCOORD2 : pif(TexBump),
      in float3 eye : TEXCOORD3,
      in float2 uv23 : TEXCOORD4,
      in float4 shadow : TEXCOORD5 : pif(Shadow!=ShadowOff),
      out float4 result : COLOR0,
    )
    {
      // bump
      float3 normal;
      pif(TexBump)
      {
        norm = normalize(norm);
        float3 tang = normalize(tangs.xyz);
        float3 bita = normalize(cross(tang,norm)*tangs.w);
        float3 tnormal = normalize(tex2D(s0,uv01.xy).xyz*2-1);
        pif(TexDetail==TexDetailBump)
        {
          float3 tnormal2 = normalize(tex2D(s2,uv23.xy).xyz*2-1);
          tnormal = normalize(tnormal+tnormal2);
        }
        normal = tnormal.x*tang + tnormal.y*bita + tnormal.z*norm;
      }
      pelse
      {
        normal = normalize(norm);
      }

      // diffuse

      pif(TexDiffuseCube)
      {
        result.xyz = texCUBE(cubediff,normal).xyz;
      }
      pelse
      {
        result.xyz = 1;//saturate(normal.x);    // this is a fake!
      }

      // main texture

      float4 diffusetex = tex2D(s1,uv01.zw);
      result.xyz *= diffusetex.xyz;
      pif(TexDetail==TexDetailMul)
      {
        result.xyz *= tex2D(s2,uv23.xy).xyz;
      }
      pif(TexDetail==TexDetailAdd)
      {
        result.xyz += tex2D(s2,uv23.xy).xyz;
      }
      
      // spec 

      pif(TexSpecularCube)
      {
        float3 envi = texCUBE(cubespec,reflect(eye,normal)).xyz;
        pif(TexDetail==TexDetailSpecMul)
          envi *= tex2D(s2,uv23.xy).xyz;
        result.xyz += envi;
      }
/*      
      pif(TexEnvi)
      {
        float3 envi = tex2D(s5,normalize(reflect(eye.xyz,normal.xyz)).xy*0.5+0.5).xyz;
        result.xyz *= envi;
      }
*/    
      pif(Shadow==ShadowReceive)
      {
        const float f = 0.04;
        float z = saturate(shadow.z/shadow.w-0.0001);
        float d;
        pif(RENDER_DX11)
          d = (tex2D(s6,(shadow.xy+float2(f* 0,f* 0))/shadow.w).x < z) * 4
            + (tex2D(s6,(shadow.xy+float2(f* 1,f* 0))/shadow.w).x < z) * 3
            + (tex2D(s6,(shadow.xy+float2(f* 0,f* 1))/shadow.w).x < z) * 3
            + (tex2D(s6,(shadow.xy+float2(f*-1,f* 0))/shadow.w).x < z) * 3
            + (tex2D(s6,(shadow.xy+float2(f* 0,f*-1))/shadow.w).x < z) * 3
            + (tex2D(s6,(shadow.xy+float2(f* 2,f* 0))/shadow.w).x < z) * 2
            + (tex2D(s6,(shadow.xy+float2(f* 0,f* 2))/shadow.w).x < z) * 2
            + (tex2D(s6,(shadow.xy+float2(f*-2,f* 0))/shadow.w).x < z) * 2
            + (tex2D(s6,(shadow.xy+float2(f* 0,f*-2))/shadow.w).x < z) * 2
            ;
        pelse
          d = (tex2Dproj(s6,shadow+float4(f* 0,f* 0,0,0)).x < z) * 4
            + (tex2Dproj(s6,shadow+float4(f* 1,f* 0,0,0)).x < z) * 3
            + (tex2Dproj(s6,shadow+float4(f* 0,f* 1,0,0)).x < z) * 3
            + (tex2Dproj(s6,shadow+float4(f*-1,f* 0,0,0)).x < z) * 3
            + (tex2Dproj(s6,shadow+float4(f* 0,f*-1,0,0)).x < z) * 3
            + (tex2Dproj(s6,shadow+float4(f* 2,f* 0,0,0)).x < z) * 2
            + (tex2Dproj(s6,shadow+float4(f* 0,f* 2,0,0)).x < z) * 2
            + (tex2Dproj(s6,shadow+float4(f*-2,f* 0,0,0)).x < z) * 2
            + (tex2Dproj(s6,shadow+float4(f* 0,f*-2,0,0)).x < z) * 2
            ;
        result.xyz *= 1-d*0.01;
      }
      pif(Shadow==ShadowReceivePS3)
      {
        float d;
        pif(RENDER_DX11)
          d = tex2D(s6,shadow.xy/shadow.w).x;
        pelse
          d = tex2Dproj(s6,shadow).x;
        result.xyz *= 1-d*0.25;
      }

      // done

//      result.xyz = 0;//normal.xyz*0.5+0.5;
      pif(Alpha==AlphaOne)
        result.w = 1;
      pif(Alpha==AlphaDist)
        result.w = sqrt(dot(eye,eye)); 
      pif(Alpha==AlphaDiffuse)
        result.w = diffusetex.w;
    }
  }

  header
  {
    static sShader *GetVS(sInt i) { return VS(i); }
    static sShader *GetPS(sInt i) { return PS(i); }
  }

  prepare
  {
    PixelShader = 0;
    VertexShader = 0;
  }
};


/****************************************************************************/
/****************************************************************************/

material Wz4LShader
{
  vs asc vs_3_0
  {
    permute Wz4LShaderVSPerm
    {
      DetailTex { DetailUV0,DetailUV1,DetailPos,DetailNorm,DetailRefl };
      SkinEnable;
    };
    use Wz4LShaderVSPerm;
    use Wz4ShaderCamera;
    use Wz4ShaderUV;
    void main
    (
      in float4 in_pos : POSITION,
      in float3 in_norm : NORMAL,           // float 3! if you use float4, it gets extendet to (x,y,z,1)!
      in float4 in_uv : TEXCOORD0,
      in int4 in_index : BLENDINDICES : pif(SkinEnable),
      in float4 in_weight : BLENDWEIGHT : pif(SkinEnable),

      out float4 out_uv01 : TEXCOORD0,
//      out float3 out_norm : TEXCOORD1,
//      out float3 out_eye : TEXCOORD3,
      out float4 out_pos : POSITION,

      uniform float4 Skinning[42] : register(c20) : pif(SkinEnable),
    )
    {

      out_uv01.x = dot(float4(in_uv.x,in_uv.y,0,1),UV[2]);
      out_uv01.y = dot(float4(in_uv.x,in_uv.y,0,1),UV[3]);

      float3 out_norm = normalize(in_norm);

      float3 out_eye = (in_pos.xyz-EyePos.xyz)*EyePos.w;

      pif(SkinEnable)
      {
        float4 sm0,sm1,sm2,n;
        
        sm0  = in_weight.x * Skinning[in_index.x+0];
        sm1  = in_weight.x * Skinning[in_index.x+1];
        sm2  = in_weight.x * Skinning[in_index.x+2];
        sm0 += in_weight.y * Skinning[in_index.y+0];
        sm1 += in_weight.y * Skinning[in_index.y+1];
        sm2 += in_weight.y * Skinning[in_index.y+2];
        sm0 += in_weight.z * Skinning[in_index.z+0];
        sm1 += in_weight.z * Skinning[in_index.z+1];
        sm2 += in_weight.z * Skinning[in_index.z+2];
        sm0 += in_weight.w * Skinning[in_index.w+0];
        sm1 += in_weight.w * Skinning[in_index.w+1];
        sm2 += in_weight.w * Skinning[in_index.w+2];
        
        n = float4(in_pos.xyz ,1);
        in_pos.x  = dot(n,sm0);
        in_pos.y  = dot(n,sm1);
        in_pos.z  = dot(n,sm2);
        n = float4(out_norm.xyz ,0);
        out_norm.x = dot(n,sm0);
        out_norm.y = dot(n,sm1);
        out_norm.z = dot(n,sm2);
        out_pos = mul(in_pos,MVP);
      }
      pelse
      {
        out_pos = mul(in_pos,MVP);
      }

      float4 uv;
      pif(DetailTex==DetailUV0)  uv = float4(in_uv.xy,0,1);
      pif(DetailTex==DetailUV1)  uv = float4(in_uv.zw,0,1);
      pif(DetailTex==DetailPos)  uv = float4(in_pos.xyz,1);
      pif(DetailTex==DetailNorm) uv = float4(in_norm.xyz,1);
      pif(DetailTex==DetailRefl)
      {
        out_uv01.zw = normalize(reflect(out_eye,in_norm.xyz)).xy*0.5+0.5;
      }
      pelse
      {
        out_uv01.z = dot(uv,UV[4]);
        out_uv01.w = dot(uv,UV[5]);
      }
    }
  }
  ps asc ps_3_0
  {
    permute Wz4LShaderPSPerm
    {
      TexDetail { TexDetailOff,TexDetailMul,TexDetailAdd };
      AlphaDiffuse;
//      TexEnvi;
    };

    sampler2D s1 : register(s1);    // color
    sampler2D s2 : register(s2);    // detail
    sampler2D s5 : register(s5);    // envi
    
    use Wz4LShaderPSPerm;

    void main
    (
      in float4 uv01 : TEXCOORD0,
//      in float3 norm : TEXCOORD1,
//      in float3 eye : TEXCOORD3,
      out float4 result : COLOR0,
    )
    {
      float4 diffuse = tex2D(s1,uv01.xy);
      result.xyz = diffuse.xyz;
      pif(TexDetail==TexDetailMul)
        result.xyz *= tex2D(s2,uv01.zw).xyz;
      pif(TexDetail==TexDetailAdd)
        result.xyz += tex2D(s2,uv01.zw).xyz;
/*      
      pif(TexEnvi)
      {
        float3 envi = tex2D(s5,normalize(reflect(eye.xyz,normalize(norm))).xy*0.5+0.5).xyz;
        result.xyz *= envi;
      }
  */    
      pif(AlphaDiffuse)
        result.w = diffuse.w;
      pelse
        result.w = 1;
    }
  }

  header
  {
    static sShader *GetVS(sInt i) { return VS(i); }
    static sShader *GetPS(sInt i) { return PS(i); }
  }

  prepare
  {
    PixelShader = 0;
    VertexShader = 0;
  }
};

/****************************************************************************/
/****************************************************************************/

material Wz4CShader
{
  vs asc vs_3_0
  {
    permute Wz4CShaderVSPerm
    {
      SkinEnable;
      ShadowPS3;
    };
    use Wz4CShaderVSPerm;
    use Wz4ShaderCamera;
    use Wz4ShaderUV;

    void main
    (
      in float4 in_pos : POSITION,
      in int4 in_index : BLENDINDICES : pif(SkinEnable),
      in float4 in_weight : BLENDWEIGHT : pif(SkinEnable),

      out float2 out_post : TEXCOORD0 : pif(!ShadowPS3),
      out float4 out_pos : POSITION,

      uniform float4 Skinning[42] : register(c20) : pif(SkinEnable),
    )
    {
      pif(SkinEnable)
      {
        float4 sm0,sm1,sm2,n;
        
        sm0  = in_weight.x * Skinning[in_index.x+0];
        sm1  = in_weight.x * Skinning[in_index.x+1];
        sm2  = in_weight.x * Skinning[in_index.x+2];
        sm0 += in_weight.y * Skinning[in_index.y+0];
        sm1 += in_weight.y * Skinning[in_index.y+1];
        sm2 += in_weight.y * Skinning[in_index.y+2];
        sm0 += in_weight.z * Skinning[in_index.z+0];
        sm1 += in_weight.z * Skinning[in_index.z+1];
        sm2 += in_weight.z * Skinning[in_index.z+2];
        sm0 += in_weight.w * Skinning[in_index.w+0];
        sm1 += in_weight.w * Skinning[in_index.w+1];
        sm2 += in_weight.w * Skinning[in_index.w+2];
        
        n = float4(in_pos.xyz ,1);
        in_pos.x  = dot(n,sm0);
        in_pos.y  = dot(n,sm1);
        in_pos.z  = dot(n,sm2);

        out_pos = mul(in_pos,MVP);
      }
      pelse
      {
        out_pos = mul(in_pos,MVP);
      }

      pif(!ShadowPS3)
        out_post.xy = out_pos.zw;
    }
  }

  ps asc ps_3_0
  {
    permute Wz4CShaderPSPerm
    {
      ShadowPS3;
    };
    use Wz4CShaderPSPerm;
    void main
    (
      in float2 post : TEXCOORD0 : pif(!ShadowPS3),
      out float4 result : COLOR0,
    )
    {
      pif(ShadowPS3)
        result = float4(0,0,0,0);
      pelse
        result = post.x/post.y;
    }
  }

  header
  {
    static sShader *GetVS(sInt i) { return VS(i); }
    static sShader *GetPS(sInt i) { return PS(i); }
  }

  prepare
  {
    PixelShader = 0;
    VertexShader = 0;
  }
};


/****************************************************************************/
/****************************************************************************/
